﻿namespace com.oakwoodsys.Extensions.StringExtensions
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Globalization;
    using System.IO;
    using System.Security;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Xml.Serialization;

    public static class StringExtensions
    {
        #region Fields

        private static Regex isNumericEx;
        private static Regex isValidEmailSyntaxEx;
        static Dictionary<string, string> _encodingPairs;

        #endregion Fields

        #region Properties

        static Dictionary<string, string> encodingPairs
        {
            get
            {
                if ( _encodingPairs == null )
                {
                    _encodingPairs = new Dictionary<string, string>( );
                    _encodingPairs.Add( "™", "&#8482;" );
                    _encodingPairs.Add( "!", "&#33;" );
                    _encodingPairs.Add( "$", "&#36;" );
                    _encodingPairs.Add( "%", "&#37;" );
                    _encodingPairs.Add( "'", "&#39;" );
                    _encodingPairs.Add( "=", "&#61;" );
                    _encodingPairs.Add( "?", "&#63;" );
                }
                return _encodingPairs;
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Append the string to this instance of System.String.
        /// </summary>
        /// <param path="a">Instance of type System.String to which a is appended.</param>
        /// <param path="b">Instance of type System.String to be appended.</param>
        /// <returns>An instance of type System.String where a is concatenated to this instance.</returns>
        public static string Append( this string a, string b )
        {
            if ( string.IsNullOrEmpty( a ) || string.IsNullOrEmpty( b ) )
                return string.Empty;
            return string.Concat( a, b );
        }

        /// <summary>
        /// Deserialies the XML formatted string and returns an object of the specified type.
        /// </summary>
        /// <typeparam name="T">Specifies the type of object to serialize.</typeparam>
        /// <param name="a"></param>
        /// <returns>If the XML formatted string can be deserialized as the specfied object, returns an object of the specified type; otherwise returns null.</returns>
        public static T DeserializeFromXml<T>( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return default( T );
            return ( T ) a.DeserializeFromXml( typeof( T ) );
        }

        /// <summary>
        /// Deserialies the XML formatted string and returns an object of the specified type.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="type">Specifies the type of object to serialize.</param>
        /// <returns>If the XML formatted string can be deserialized as the specfied object, returns an object of the specified type; otherwise returns null.</returns>
        public static object DeserializeFromXml( this string a, Type type )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            XmlSerializer s = new XmlSerializer( type );
            using ( MemoryStream stream = new MemoryStream( a.ToArray( ) ) )
            {
                return s.Deserialize( stream );
            }
        }

        /// <summary>
        /// Checks for existence of the specified directory path.
        /// </summary>
        /// <param name="a">Instance of type System.String for which the directory existence is checked.</param>
        /// <returns>true if the directory exists, otherwise false.</returns>
        public static bool DirectoryExists( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            if ( a.IsDirectoryNameLegal( ) )
            {
                DirectoryInfo di = new DirectoryInfo( a );
                bool ok = di.Exists;
                di = null;
                return ok;
            }
            else
                return false;
        }

        /// <summary>
        /// Checks for existence of the specified file.
        /// </summary>
        /// <param name="a">Instance of type System.String for which the file existence is checked.</param>
        /// <returns>true if the file exists, otherwise false.</returns>
        public static bool FileExists( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            if ( a.IsFileNameLegal( ) )
            {
                FileInfo fi = new FileInfo( a );
                bool ok = fi.Exists;
                fi = null;
                return ok;
            }
            else
                return false;
        }

        /// <summary>
        /// Converts the instance of System.String encoded with base 64 digits to its equivalent System.String representation.
        /// </summary>
        /// <param name="a">An instance of System.String encoded with base 64 digits.</param>
        /// <returns>An instance of System.String.</returns>
        public static string FromBase64String( this string a )
        {
            return Encoding.Default.GetString( Convert.FromBase64String( a ) );
        }

        public static byte[] FromBase64StringToArray( this string a )
        {
            return Convert.FromBase64String( a );
        }

        /// <summary>
        /// Convert this specified instance of a short Guid (a 22-byte string) to a Guid. To convert a Guid to a short Guid, see GuidExtensions.ToShortGuid.
        /// </summary>
        /// <param name="shortGuid"></param>
        /// <returns></returns>
        public static Guid FromShortGuid( this string shortGuid )
        {
            string s = shortGuid.Replace( "_", "/" ).Replace( "-", "+" );
            byte[ ] b = Convert.FromBase64String( string.Format( "{0}==", s ) );
            return new Guid( b );
        }

        /// <summary>
        /// Get the file contents as a byte array. If the string represents an existing file, then return the file contents as a byte array, otherwise return null.
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static byte[] GetFileAsArray( this string a )
        {
            if ( a.FileExists( ) )
            {
                FileInfo fi = new FileInfo( a );
                if ( fi.Exists )
                {
                    using ( FileStream stream = ( FileStream ) new StreamReader( a ).BaseStream )
                    {
                        //byte[ ] b = new byte[ stream.Length ];
                        //stream.Read ( b, 0, ( Int32 ) stream.Length );
                        //stream.Flush ( );
                        //stream.Close ( );
                        //stream.Dispose ( );
                        //return b;

                        List<byte> b = new List<byte>( );
                        try
                        {
                            using ( BinaryReader r = new BinaryReader( stream ) )
                            {
                                while ( 0 == 0 )
                                    b.Add( r.ReadByte( ) );
                            }
                        }
                        catch ( EndOfStreamException )
                        {
                        }
                        return b.ToArray( );
                    }
                }
            }
            return null;
        }

        public static string HtmlDecode( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return string.Empty;
            string s = HttpUtility.HtmlDecode( a );
            foreach ( var v in encodingPairs )
                s = s.Replace( v.Value, v.Key );
            return s;
        }

        public static string HtmlEncode( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return string.Empty;
            string s = HttpUtility.HtmlEncode( a );
            foreach ( var v in encodingPairs )
                s = s.Replace( v.Key, v.Value );
            return s;
        }

        /// <summary>
        /// Determines if the System.String is a valid representation of a date and time.
        /// </summary>
        /// <param path="a">Instance of type System.String used to determine validity.</param>
        /// <returns>true if the System.String is a valid representation of a date and time, otherwise returns false.</returns>
        public static bool IsDateTime( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            DateTime dt;
            bool ok = DateTime.TryParse( a, CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out dt );
            if ( ok )
                return true;
            else
                return false;
        }

        /// <summary>
        /// Determines if the directory path is syntactically correct.
        /// </summary>
        /// <param name="a">Instance of type System.String which is checked for syntax correctness as a name of a directory path.</param>
        /// <returns>true if the directory path is syntactically correct, otherwise false;</returns>
        public static bool IsDirectoryNameLegal( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            return verifySyntaxLegality( a, Path.GetInvalidPathChars( ) );
        }

        /// <summary>
        /// Determines if the file name is syntactically correct. If the string represents a full qualified file name, then the file name and the directory name are syntactically verified.
        /// </summary>
        /// <param name="a">Instance of type System.String which is checked for syntax correctness as a name of a file path.</param>        /// <returns>true if the file name is syntactically correct, otherwise false.</returns>
        public static bool IsFileNameLegal( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            string[ ] s = a.Split( Path.DirectorySeparatorChar );

            string file = s[ s.Length - 1 ];
            bool fileOk = true;
            if ( !string.IsNullOrEmpty( file ) )
                fileOk = verifySyntaxLegality( file, Path.GetInvalidFileNameChars( ) );
            else
                fileOk = false;

            StringBuilder sb = new StringBuilder( );
            for ( int i = 0; i < s.Length - 1; i++ )
            {
                sb.Append( s[ i ] );
                sb.Append( Path.DirectorySeparatorChar );
            }
            bool pathOk = true;
            string path = sb.ToString( );
            sb = null;
            if ( !string.IsNullOrEmpty( path ) )
                pathOk = verifySyntaxLegality( path, Path.GetInvalidPathChars( ) );
            else
                pathOk = false;

            return pathOk && fileOk;
        }

        public static bool IsLike( this string a, string b, StringComparison comparisonType )
        {
            const string wildcard = "*";

            string l;
            if ( string.IsNullOrEmpty( a ) || string.IsNullOrEmpty( b ) )
            {
                return false;
            }
            if ( b.StartsWith( wildcard ) && b.EndsWith( wildcard ) )
            {
                l = b.Remove( b.Length - 1, 1 ).Remove( 0, 1 );
                return ( a.IndexOf( l, comparisonType ) >= 0 );
            }
            if ( b.StartsWith( wildcard ) )
            {
                l = b.Remove( 0, 1 );
                return a.EndsWith( l, comparisonType );
            }
            if ( b.EndsWith( wildcard ) )
            {
                l = b.Remove( b.Length - 1, 1 );
                return a.StartsWith( l, comparisonType );
            }
            return a.Equals( b, comparisonType );
        }

        /// <summary>
        /// Determines if the System.String is numeric. It is culture aware. It looks at the character string for the following culture aware symbols and separators: currency decimal separator, currency group separator, currency symbol, negative sign, negative infinity symbol, number decimal separator, number group separator, percent decimal separator, percent group separator, percent symbol, per mille symbol, positive infinity symbol, and positive sign.
        /// </summary>
        /// <param path="a">Instance of type System.String used to determine validity.</param>
        /// <returns>true if the character string is numeric, otherwise false</returns>
        public static bool IsNumeric( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            string s = stripCultureAwareNumberFormatInfoStrings( stripCultureAwareStrings( a ) );
            if ( string.IsNullOrEmpty( s ) )
                return false;
            if ( isNumericEx == null )
                isNumericEx = new Regex( "^(?<number>[0-9])+$" );

            Match match = isNumericEx.Match( s );
            return match.Success;
        }

        /// <summary>
        /// Determines if the character string is a valid representation of an Email address.
        /// </summary>
        /// <param path="value">Instance of type System.String used to determine validity.</param>
        /// <returns>true if the System.String is a valid representation of an Email address, otherwise false.</returns>
        public static bool IsValidEmailSyntax( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;

            if ( isValidEmailSyntaxEx == null )
                isValidEmailSyntaxEx = new Regex( @"^((?>[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+\x20*|&quot;((?=[\x01-\x7f])[^&quot;\\]|\\[\x01-\x7f])*&quot;\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+)+|&quot;((?=[\x01-\x7f])[^&quot;\\]|\\[\x01-\x7f])*&quot;)@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$".Replace( "&quot;", "\"" ), RegexOptions.IgnoreCase );
            // new Regex( @"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$", RegexOptions.IgnoreCase );

            Match match = isValidEmailSyntaxEx.Match( a.Trim( ) );
            return match.Success;
        }

        public static string PadRightToBoundary( this string a, int boundary )
        {
            if ( boundary <= 0 )
                return a;
            int x = a.Length % boundary;
            int y = x == 0 ? 0 : boundary - x;
            return a.PadRight( a.Length + y );
        }

        public static string PadRightToBoundary( this string a, int boundary, char paddingChar )
        {
            int x = a.Length % boundary;
            int y = x == 0 ? 0 : boundary - x;
            return a.PadRight( a.Length + y, paddingChar );
        }

        /// <summary>
        /// Prepend the string to this instance of System.String.
        /// </summary>
        /// <param path="a">Instance of type System.String to which a is prepended.</param>
        /// <param path="b">Instance of type System.String to be prepended.</param>
        /// <returns>An instance of type System.String where this instance is concatenated to a.</returns>
        public static string Prepend( this string a, string b )
        {
            if ( string.IsNullOrEmpty( a ) || string.IsNullOrEmpty( b ) )
                return string.Empty;
            return string.Concat( b, a );
        }

        /// <summary>
        /// Remove punctuation from this instance of System.String.
        /// </summary>
        /// <param name="a">Instance of type System.String from which punctuation is removed.</param>
        /// <returns>An instance of type System.String where all punctuation has been removed.</returns>
        public static string RemovePunctuation( this string a )
        {
            char[ ] c = a.ToCharArray( );
            StringBuilder sb = new StringBuilder( );
            foreach ( var v in c )
                if ( Char.IsLetterOrDigit( v ) || Char.IsWhiteSpace( v ) )
                    sb.Append( v );
            string s = sb.ToString( );
            sb = null;
            return s;
        }

        /// <summary>
        /// Remove whitespace from this instance of System.String.
        /// </summary>
        /// <param name="a">Instance of type System.String from which whitespace is removed.</param>
        /// <returns>An instance of type System.String where all whitespace has been removed.</returns>
        public static string RemoveWhiteSpace( this string a )
        {
            char[ ] c = a.ToCharArray( );
            StringBuilder sb = new StringBuilder( );
            foreach ( var v in c )
                if ( !Char.IsWhiteSpace( v ) )
                    sb.Append( v );
            string s = sb.ToString( );
            sb = null;
            return s;
        }

        /// <summary>
        /// Returns an empty string if the specified string is null, otherwise returns the specified string trimmed.
        /// </summary>
        /// <param name="a">The string to trim.</param>
        /// <returns>If the specified string is null, an empty string; otherwise the specified string trimmed.</returns>
        public static string SafeTrim( this string a )
        {
            return string.IsNullOrEmpty( a ) ? string.Empty : a.Trim( );
        }

        public static string StripHTML( this string a )
        {
            const string HTMLTAGPATTERN = "<.*?>";
            string s = string.IsNullOrEmpty( a ) ? string.Empty : a;
            return Regex.Replace( s, HTMLTAGPATTERN, string.Empty );
        }

        /// <summary>
        /// Encodes the specified string into a sequence of bytes. The encoding for the operating system's current ANSI code page is utilized to encode the specified string.
        /// </summary>
        /// <param name="a">The string to encode.</param>
        /// <returns>A byte array containing the results of encoding the specified string.</returns>
        public static byte[] ToArray( this string a )
        {
            return a.ToByteArray( System.Text.Encoding.Default );
        }

        /// <summary>
        /// Encodes the specified string into a sequence of bytes.
        /// </summary>
        /// <param name="a">The string to encode.</param>
        /// <param name="encoding">The encoding to utilize to encode the specified string.</param>
        /// <returns>A byte array containing the results of encoding the specified string.</returns>
        public static byte[] ToArray( this string a, System.Text.Encoding encoding )
        {
            System.Text.Encoding e = encoding as System.Text.Encoding;
            if ( e == null )
                e = System.Text.Encoding.Default;
            return e.GetBytes( a.ToCharArray( ) );
        }

        /// <summary>
        /// Converts the instance of System.String to its equivalent System.String representation encoded with base 64 digits.
        /// </summary>
        /// <param name="a">An instance of System.String.</param>
        /// <returns>An instance of System.String encoded with base 64 digits.</returns>
        public static string ToBase64String( this string a )
        {
            return Convert.ToBase64String( Encoding.Default.GetBytes( a.ToCharArray( ) ) );
        }

        /// <summary>
        /// Convert the string to a System.Boolean. If the string equals "on" or "true" or "1", return true; otherwise false.
        /// </summary>
        /// <param name="a">Instance of type System.String to be converted.</param>
        /// <returns>true if the string equals "on" or "true" or "1", otherwise false.</returns>
        /// <remarks>Change 2010/12/30: Added equality to "1" return true.</remarks>
        public static Boolean ToBoolean( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return false;
            if ( a.Equals( "on", StringComparison.OrdinalIgnoreCase ) || a.Equals( "true", StringComparison.OrdinalIgnoreCase ) || a.StartsWith( "t", StringComparison.OrdinalIgnoreCase ) || a.Equals( "1" ) )
                return true;
            else
                return false;
        }

        /// <summary>
        /// Encodes the specified string into a sequence of bytes. The encoding for the operating system's current ANSI code page is utilized to encode the specified string.
        /// </summary>
        /// <param name="a">The string to encode.</param>
        /// <returns>A byte array containing the results of encoding the specified string.</returns>
        public static byte[] ToByteArray( this string a )
        {
            return a.ToArray( System.Text.Encoding.Default );
        }

        /// <summary>
        /// Encodes the specified string into a sequence of bytes.
        /// </summary>
        /// <param name="a">The string to encode.</param>
        /// <param name="encoding">The encoding to utilize to encode the specified string.</param>
        /// <returns>A byte array containing the results of encoding the specified string.</returns>
        public static byte[] ToByteArray( this string a, System.Text.Encoding encoding )
        {
            return a.ToArray( encoding );
        }

        /// <summary>
        /// Convert the instance of System.String to a new instance of System.Data.Linq.Binary.
        /// </summary>
        /// <param name="a">An instance of System.String which encodes an instance of System.Data.Linq.Binary as base 64 digits.</param>
        /// <returns>A new instance of System.Data.Linq.Binary created from the encoded instance of System.String.</returns>
        public static System.Data.Linq.Binary ToDataLinqBinary( this string a )
        {
            return new System.Data.Linq.Binary( Convert.FromBase64String( a ) );
        }

        public static DataTable ToDataTable<T>( this IList<T> data )
        {
            PropertyDescriptorCollection props =
                TypeDescriptor.GetProperties( typeof( T ) );
            DataTable table = new DataTable( );
            for ( int i = 0; i < props.Count; i++ )
            {
                PropertyDescriptor prop = props[ i ];
                table.Columns.Add( prop.Name, prop.PropertyType );
            }
            object[ ] values = new object[ props.Count ];
            foreach ( T item in data )
            {
                for ( int i = 0; i < values.Length; i++ )
                {
                    values[ i ] = props[ i ].GetValue( item );
                }
                table.Rows.Add( values );
            }
            return table;
        }

        /// <summary>
        /// Converts the specified string representation of a date and time to its System.DateTime equivalent. If not a valid string representation of a date and time, returns a System.DateTime with a minimum value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a date and time, returns its System.DateTime equivalent, otherwise returns a System.DateTime with a minimum value.</returns>
        public static DateTime ToDateTime( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return new DateTime( );
            DateTime dt;
            bool ok = DateTime.TryParse( a, CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out dt );
            if ( ok )
                return dt;
            else
                return new DateTime( );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Decimal equivalent. If not a valid string representation of a number, returns a System.Decimal with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Decimal equivalent, otherwise returns a System.Decimal with a value of 0.</returns>
        public static decimal ToDecimal( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            return d;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Double equivalent. If not a valid string representation of a number, returns a System.Double with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Double equivalent, otherwise returns a System.Double with a value of 0.</returns>
        public static Double ToDouble( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Double d = 0;
            bool ok = Double.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            return d;
        }

        /// <summary>
        /// Returns an empty string if the specified string is null, otherwise returns the specified string.
        /// </summary>
        /// <param name="a">The string to test.</param>
        /// <returns>If the specified string is null, an empty string; otherwise the specified string.</returns>
        public static string ToEmptyStringIfNull( this string a )
        {
            return string.IsNullOrEmpty( a ) ? string.Empty : a;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Single (single-precision floating-point number) equivalent. If not a valid string representation of a number, returns a System.Single with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Single equivalent, otherwise returns a System.Single with a value of 0.</returns>
        public static Single ToFloat( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            return a.ToSingle( );
        }

        public static Guid ToGuid( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return Guid.Empty;
            return new Guid( a );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int16 equivalent. If not a valid string representation of a number, returns a System.Int16 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Int16 equivalent, otherwise returns a System.Int16 with a value of 0.</returns>
        public static int ToInt16( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            return Decimal.ToInt16( Decimal.Round( d, 0 ) );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int16 equivalent. If not a valid string representation of a number, returns a System.Int16 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Int16 equivalent, otherwise returns a System.Int16 with a value of 0.</returns>
        public static Int16 ToInt16( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Int16 i = 0;
            bool ok = Int16.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            return i;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int32 equivalent using the specified style and culture-specific format. If not a valid string representation of a number, returns a System.Int32 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Int32 equivalent, otherwise returns a System.Int32 with a value of 0.</returns>
        public static Int32 ToInt32( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            return Decimal.ToInt32( Decimal.Round( d, 0 ) );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int32 equivalent. If not a valid string representation of a number, returns a System.Int32 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Int32 equivalent, otherwise returns a System.Int32 with a value of 0.</returns>
        public static Int32 ToInt32( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Int32 i = 0;
            bool ok = Int32.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            return i;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int64 equivalent. If not a valid string representation of a number, returns a System.Int64 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Int64 equivalent, otherwise returns a System.Int64 with a value of 0.</returns>
        public static Int64 ToInt64( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            return Decimal.ToInt64( Decimal.Round( d, 0 ) );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Int64 equivalent. If not a valid string representation of a number, returns a System.Int64 with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Int64 equivalent, otherwise returns a System.Int64 with a value of 0.</returns>
        public static Int64 ToInt64( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Int64 i = 0;
            bool ok = Int64.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            return i;
        }

        public static string ToLegalFileName( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
            {
                return "New File";
            }
            string[ ] s = a.Split( new char[ ] { Path.DirectorySeparatorChar } );
            string file = s[ s.Length - 1 ];
            if ( string.IsNullOrEmpty( file ) )
            {
                return "New File";
            }
            foreach ( char c in Path.GetInvalidFileNameChars( ) )
            {
                file = file.Replace( c.ToString( CultureInfo.InvariantCulture ), " " );
            }
            return file;
        }

        /// <summary>
        /// Converts the specified string representation of a boolean to its System.Nullable&lt;Boolean&gt; equivalent. If the string is null or empty returns a null, else true if the string equals "on" or "true", otherwise false.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If the string is null or empty returns a null, else true if the string equals "on" or "true", otherwise false.</returns>
        public static Boolean? ToNullableBoolean( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            if ( a.Equals( "on", StringComparison.OrdinalIgnoreCase ) || a.Equals( "true", StringComparison.OrdinalIgnoreCase ) || a.StartsWith( "t", StringComparison.OrdinalIgnoreCase ) )
                return true;
            else
                return false;
        }

        /// <summary>
        /// Converts the specified string representation of a date and time to its System.Nullable&lt;DateTime&gt; equivalent. If not a valid string representation of a date and time, returns a System.Nullable&lt;DateTime&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a date and time, returns its System.DateTime equivalent, otherwise returns a System.DateTime with a minimum value.</returns>
        public static DateTime? ToNullableDateTime( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            DateTime dt;
            bool ok = DateTime.TryParse( a, CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out dt );
            if ( ok )
                return dt;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable<Decimal> equivalent. If not a valid string representation of a number, returns a System.Nullable<Decimal> with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable<Decimal> equivalent, otherwise returns a System.Nullable<Decimal> with a null value.</returns>
        public static decimal? ToNullableDecimal( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            if ( ok )
                return d;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable<Double> equivalent. If not a valid string representation of a number, returns a System.Nullable<Double> with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable<Double> equivalent, otherwise returns a System.Nullable<Double> with a null value.</returns>
        public static Double? ToNullableDouble( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Double d = 0;
            bool ok = Double.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            if ( ok )
                return d;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Single&gt; (single-precision floating-point number) equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Single&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Single&gt; equivalent, otherwise returns a System.Nullable&lt;Single&gt; with a null value.</returns>
        public static Single? ToNullableFloat( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            return a.ToNullableSingle( );
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int16&gt; equivalent using the specified style and culture-specific format. If not a valid string representation of a number, returns a System.Nullable&lt;Int16&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int16&gt; equivalent, otherwise returns a System.Nullable&lt;Int16&gt; with a null value.</returns>
        public static Int16? ToNullableInt16( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            if ( ok )
                return Decimal.ToInt16( Decimal.Round( d, 0 ) );
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int16&gt; equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Int16&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int16&gt; equivalent, otherwise returns a System.Nullable&lt;Int16&gt; with a null value.</returns>
        public static Int16? ToNullableInt16( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Int16 i = 0;
            bool ok = Int16.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            if ( ok )
                return i;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int32&gt; equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Int32&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int32&gt; equivalent, otherwise returns a System.Nullable&lt;Int32&gt; with a null value.</returns>
        public static Int32? ToNullableInt32( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Int32 i = 0;
            bool ok = Int32.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            if ( ok )
                return i;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int32&gt; equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Int32&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int32&gt; equivalent, otherwise returns a System.Nullable&lt;Int32&gt; with a null value.</returns>
        public static Int32? ToNullableInt32( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            if ( ok )
                return Decimal.ToInt32( Decimal.Round( d, 0 ) );
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int64&gt; equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Int64&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <param name="numberStyle">A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of the string. A typical value to specify is System.Globalization.NumberStyles.HexNumber.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int64&gt; equivalent, otherwise returns a System.Nullable&lt;Int64&gt; with a null value.</returns>
        public static Int64? ToNullableInt64( this string a, NumberStyles numberStyle )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Int64 i = 0;
            bool ok = Int64.TryParse( s, numberStyle, CultureInfo.CurrentCulture, out i );
            if ( ok )
                return i;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable&lt;Int64&gt; equivalent. If not a valid string representation of a number, returns a System.Nullable&lt;Int64&gt; with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable&lt;Int64&gt; equivalent, otherwise returns a System.Nullable&lt;Int64&gt; with a null value.</returns>
        public static Int64? ToNullableInt64( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Decimal d = 0;
            bool ok = Decimal.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out d );
            if ( ok )
                return Decimal.ToInt64( Decimal.Round( d, 0 ) );
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Nullable<Single> (single-precision floating-point number) equivalent. If not a valid string representation of a number, returns a System.Nullable<Single> with a null value.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Nullable<Single> equivalent, otherwise returns a System.Nullable<Single> with a null value.</returns>
        public static Single? ToNullableSingle( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;
            string s = stripCultureAwareStrings( a );
            Single f = 0;
            bool ok = Single.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out f );
            if ( ok )
                return f;
            else
                return null;
        }

        /// <summary>
        /// Converts the System.String to its RomanNumeral equivalent.
        /// </summary>
        /// <param name="a">Instance of type System.String to be converted.</param>
        /// <returns>Instance of type RomanNumeral.</returns>
        public static RomanNumeral ToRomanNumeral( this string a )
        {
            return new RomanNumeral( a );
        }

        /// <summary>
        /// Return an instance of type System.Security.SecureString with the value of this instance of System.String.
        /// </summary>
        /// <param name="a">Instance of type System.String from which an instance of type System.Security.SecureString is created.</param>
        /// <returns>An instance of type System.Security.SecureString with the value of this instance of type System.String.</returns>
        public static SecureString ToSecureString( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return null;

            SecureString s = new SecureString( );
            foreach ( var c in a.ToCharArray( ) )
                s.AppendChar( c );

            return s;
        }

        /// <summary>
        /// Converts the System.String representation of a number to its System.Single (single-precision floating-point number) equivalent. If not a valid string representation of a number, returns a System.Single with a value of 0.
        /// </summary>
        /// <param path="a">Instance of type System.String to be converted.</param>
        /// <returns>If valid string representation of a number, returns its System.Single equivalent, otherwise returns a System.Single with a value of 0.</returns>
        public static Single ToSingle( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return 0;
            string s = stripCultureAwareStrings( a );
            Single f = 0;
            bool ok = Single.TryParse( s, NumberStyles.Any, CultureInfo.CurrentCulture, out f );
            return f;
        }

        /// <summary>
        /// Converts the System.String to its Soundex equivalent.
        /// </summary>
        /// <param path="value">Instance of type System.String to be converted.</param>
        /// <returns>An instance of System.String that is the Soundex equivalent of this instance.</returns>
        public static string ToSoundex( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return string.Empty;
            string result = string.Empty;

            if ( !String.IsNullOrEmpty( a ) )
            {
                string v = a.ToUpperInvariant( );
                if ( Char.IsLetter( v.ToCharArray( 0, 1 )[ 0 ] ) ) // 1st character must be a letter
                {
                    // flush all but characters
                    StringBuilder temp = new StringBuilder( );
                    foreach ( char c in v.ToCharArray( ) )
                    {
                        if ( Char.IsLetter( c ) )
                            temp.Append( c );
                        else if ( c.ToString( CultureInfo.InvariantCulture ) == " " )
                            temp.Append( c );
                    }
                    v = temp.ToString( );

                    // replace special abbreviations
                    temp = new StringBuilder( );
                    if ( v.StartsWith( "ST " ) )
                    {
                        temp.Append( "SAINT" );
                        temp.Append( v.Substring( 2 ) );
                        v = temp.ToString( );
                    }

                    // append 1st letter to result
                    StringBuilder sb = new StringBuilder( );
                    sb.Append( v.Substring( 0, 1 ) );

                    // convert to soundex
                    foreach ( char c in v.Substring( 1 ).ToCharArray( ) )
                        sb.Append( getSoundexCategory( c ) );

                    // remove duplicates
                    result = sb.ToString( );
                    while ( result.IndexOf( "11" ) >= 0 || result.IndexOf( "22" ) >= 0 || result.IndexOf( "33" ) >= 0 || result.IndexOf( "44" ) >= 0 || result.IndexOf( "55" ) >= 0 || result.IndexOf( "66" ) >= 0 )
                        result = result.Replace( "11", "1" ).Replace( "22", "2" ).Replace( "33", "3" ).Replace( "44", "4" ).Replace( "55", "5" ).Replace( "66", "6" );

                    // remove vowel place holders
                    result = result.Replace( "0", string.Empty ).Trim( );

                    // size to length of 4
                    result = string.Format( CultureInfo.InvariantCulture, "{0}0000", result ).Substring( 0, 4 );
                }
            }

            return result;
        }

        /// <summary>
        /// Convert the instance of System.String, which encodes binary data as base 64 digits, to an equivalent string.
        /// </summary>
        /// <param name="a">An instance of System.String which encodes binary data as base 64 digits.</param>
        /// <returns>An instance of System.String as an equivalent to the encoded data.</returns>
        public static string ToStringFromBase64String( this string a )
        {
            return Encoding.Default.GetString( Convert.FromBase64String( a ) );
        }

        public static string ToTelephoneFormat( this string a )
        {
            string s = a.PadLeft( 10, '0' );
            return string.Format( "({0}) {1}-{2}", s.Substring( 0, 3 ), s.Substring( 3, 3 ), s.Substring( 6, 4 ) );
        }

        /// <summary>
        /// Convert the System.String representation of a System.TimeSpan to its System.TimeSpan equivalent. If not a valid string representation of a TimeSpan, returns a new instance of System.TimeSpan. The string can be delimited by ':' or '.', e.g. 1:2:3:4 returns a TimeSpan valued 1 day, 2 hours, 3 minutes, 4 seconds; 1:2:3 returns a TimeSpan valued 1 hour, 2 minutes, 3 seconds; 1:2 returns a TimeSpan valued 1 hour, 2 minutes, 0 seconds; 1 returns a TimeSpan valued 1 hour, 0 minutes, 0 seconds.
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static TimeSpan ToTimeSpan( this string a )
        {
            if ( string.IsNullOrEmpty( a ) )
                return new TimeSpan( );

            string[ ] s = new string[ 0 ];
            if ( a.Contains( ":" ) )
                s = a.Split( ':' );
            else if ( a.Contains( "." ) )
                s = a.Split( '.' );
            else
                return new TimeSpan( );

            if ( s.Length == 4 ) // days:hours:minutes:seconds
                return new TimeSpan( s[ 0 ].ToInt32( ), s[ 1 ].ToInt32( ), s[ 2 ].ToInt32( ), s[ 3 ].ToInt32( ) );
            else if ( s.Length == 3 ) // hours:minutes:seconds
                return new TimeSpan( s[ 0 ].ToInt32( ), s[ 1 ].ToInt32( ), s[ 2 ].ToInt32( ) );
            else if ( s.Length == 2 ) // hours:minutes:seconds
                return new TimeSpan( s[ 0 ].ToInt32( ), s[ 1 ].ToInt32( ), 0 );
            else // hours:minutes:seconds
                return new TimeSpan( s[ 0 ].ToInt32( ), 0, 0 );
        }

        public static string TrimNewLine( this string a )
        {
            return string.IsNullOrEmpty( a ) ? string.Empty : a.Trim( ).Trim( Environment.NewLine.ToCharArray( ) );
        }

        public static string UrlDecode( this string a )
        {
            string s = HttpUtility.UrlDecode( a );
            return s;
        }

        public static string UrlEncode( this string a )
        {
            string s = HttpUtility.UrlEncode( a );
            return s;
        }

        private static string getSoundexCategory( char value )
        {
            string s = value.ToString( CultureInfo.InvariantCulture );

            string[ ] c = new string[ ] { "AEIOUY", "BPFV", "CSKGJQXZ", "DT", "L", "MN", "R" };

            for ( int i = c.GetLowerBound( 0 ); i <= c.GetUpperBound( 0 ); i++ )
                if ( c[ i ].Contains( s ) )
                    return i.ToString( CultureInfo.InvariantCulture );

            return string.Empty;
        }

        private static string stripCultureAwareNumberFormatInfoStrings( string value )
        {
            return value.Replace( NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator, "" ).Replace( NumberFormatInfo.CurrentInfo.NegativeSign, "" ).Replace( NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "" ).Replace( NumberFormatInfo.CurrentInfo.PercentDecimalSeparator, "" );
        }

        private static string stripCultureAwareStrings( string value )
        {
            return value.Replace( NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator, "" ).Replace( NumberFormatInfo.CurrentInfo.CurrencySymbol, "" ).Replace( NumberFormatInfo.CurrentInfo.NegativeInfinitySymbol, "" ).Replace( NumberFormatInfo.CurrentInfo.NumberGroupSeparator, "" ).Replace( NumberFormatInfo.CurrentInfo.PercentGroupSeparator, "" ).Replace( NumberFormatInfo.CurrentInfo.PercentSymbol, "" ).Replace( NumberFormatInfo.CurrentInfo.PerMilleSymbol, "" ).Replace( NumberFormatInfo.CurrentInfo.PositiveInfinitySymbol, "" ).Replace( NumberFormatInfo.CurrentInfo.PositiveSign, "" ).Trim( );
        }

        private static bool verifySyntaxLegality( string value, char[ ] invalidChars )
        {
            bool ok = true;
            if ( !string.IsNullOrEmpty( value ) )
            {
                foreach ( char c in invalidChars )
                    if ( value.Contains( c.ToString( CultureInfo.InvariantCulture ) ) )
                    {
                        ok = false;
                        break;
                    }
            }
            else
                ok = false;

            return ok;
        }

        #endregion Methods
    }
}